package com.pai4j.pgc.service.community;
import com.fasterxml.jackson.core.type.TypeReference;
import com.pai4j.common.bean.PAIPageResponseBeanUtil;
import com.pai4j.common.util.DateUtils;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.common.util.RedisUtil;
import com.pai4j.domain.community.vo.DictConfigResponseVO;
import com.pai4j.domain.community.DictConfigSaveOrUpdateVO;
import com.pai4j.domain.community.vo.request.live.LiveConfigVO;
import com.pai4j.pgc.dao.community.IDictConfigDAO;
import com.pai4j.pgc.entity.community.DictConfigEntity;
import com.pai4j.remote.user.UserServiceClient;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import com.pai4j.common.enums.RedisKeyEnum;

/**
 *
 *
 * @author: CYM-pai
 * @date: 2025/10/27 14:57
 **/
@Service
public class DictConfigService {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserServiceClient userServiceClient;
    @Autowired
    private IDictConfigDAO dictConfigDAO;

    public Long saveOrUpdate(DictConfigSaveOrUpdateVO dictConfigSaveOrUpdateVO) {
        String userId = userServiceClient.getLoginUserIdAndCheckoutAdmin();
        DictConfigEntity entity = convertVoToEntity(dictConfigSaveOrUpdateVO, userId);
        entity = dictConfigDAO.save(entity);
        return entity.getId();
    }

    public Long saveLiveDictConfig(LiveConfigVO liveConfigVO) {
        String liveDictCode = "LIVE_CONFIG";
        DictConfigEntity dictConfigEntity = dictConfigDAO.findAllByCode(liveDictCode);
        if (dictConfigEntity == null) {
            dictConfigEntity = new DictConfigEntity();
        }
        dictConfigEntity.setCode(liveDictCode);
        dictConfigEntity.setName(liveDictCode);
        dictConfigEntity.setValue(JsonUtil.toJsonString(liveConfigVO));
        dictConfigEntity.setScore(0L);
        dictConfigEntity.setStatus(Boolean.TRUE);
        dictConfigEntity = dictConfigDAO.save(dictConfigEntity);
        refreshDictConfigCache(liveDictCode);
        return dictConfigEntity.getId();
    }

    public LiveConfigVO getLiveConfig() {
        String liveDictCode = "LIVE_CONFIG";
        DictConfigResponseVO live = getLatestDictConfigVOListFromCache(liveDictCode);
        if (live == null) {
            return null;
        }
        return JsonUtil.fromJson(live.getValue(), LiveConfigVO.class);
    }

    public void putOn(Long id) {
        String userId = userServiceClient.getLoginUserIdAndCheckoutAdmin();
        DictConfigEntity entity = dictConfigDAO.findAllById(id);
        Assert.isTrue(entity != null, "字典不存在");
        entity.setUpdateBy(userId);
        entity.setStatus(Boolean.TRUE);
        entity.setUpdateDate(new Date());
        dictConfigDAO.save(entity);
        refreshDictConfigCache(entity.getCode());
    }

    public void putOff(Long id) {
        String userId = userServiceClient.getLoginUserIdAndCheckoutAdmin();
        DictConfigEntity entity = dictConfigDAO.findAllById(id);
        Assert.isTrue(entity != null, "字典不存在");
        entity.setUpdateBy(userId);
        entity.setStatus(Boolean.FALSE);
        entity.setUpdateDate(new Date());
        dictConfigDAO.save(entity);
        refreshDictConfigCache(entity.getCode());
    }

    /***
     * 根据ID查询字典Value
     * @param dictId
     * @return
     */
    public String getDictValueFromCache(Long dictId) {
        DictConfigResponseVO dictConfigResponseVO = getDictConfigVOFromCache(dictId);
        if (dictConfigResponseVO == null) {
            return null;
        }
        return dictConfigResponseVO.getValue();
    }

    public DictConfigResponseVO getDictConfigVOFromCache(Long dictId) {
        String key = RedisKeyEnum.DICT_CONFIG_CACHE.getKey();
        String val = redisUtil.hget(key, String.valueOf(dictId));
        if (StringUtils.isNotBlank(val)) {
            return JsonUtil.fromJson(val, DictConfigResponseVO.class);
        }
        DictConfigEntity dictConfigEntity = dictConfigDAO.findById(dictId).orElse(null);
        DictConfigResponseVO dictConfigResponseVO = new DictConfigResponseVO();
        if (dictConfigEntity != null) {
            BeanUtils.copyProperties(dictConfigEntity, dictConfigResponseVO);
        } else {
            dictConfigResponseVO.setId(dictId);
            dictConfigResponseVO.setCode("NOT_FOUND");
            dictConfigResponseVO.setName("NOT_FOUND");
            dictConfigResponseVO.setValue("NOT_FOUND");
            dictConfigResponseVO.setScore(0L);
            dictConfigResponseVO.setStatus(true);
        }
        redisUtil.hset(key, String.valueOf(dictId), JsonUtil.toJsonString(dictConfigResponseVO), RedisKeyEnum.DICT_CONFIG_CACHE.getExpireTime());
        return dictConfigResponseVO;
    }

    public List<DictConfigResponseVO> getDictConfigVOListFromCache(String code) {
        String key = RedisKeyEnum.DICT_CONFIG_LIST_CACHE.getKey(code);
        if (!redisUtil.exists(key)) {
            List<DictConfigEntity> list = dictConfigDAO.findAllByCodeAndStatusOrderByScoreDesc(code, true);
            if (CollectionUtils.isNotEmpty(list)) {
                // 重新初始化
                redisUtil.set(key, JsonUtil.toJsonString(convertVoList(list)), RedisKeyEnum.DICT_CONFIG_LIST_CACHE.getExpireTime());
            }
        }
        String val = redisUtil.get(key);
        if (StringUtils.isNotBlank(val)) {
            return JsonUtil.fromJson(val, new TypeReference<List<DictConfigResponseVO>>() { });
        }
        List<DictConfigResponseVO> list = new ArrayList<>();
        if (code.startsWith("STAR_NAV_")) {
            // 默认创建一个字典项
            DictConfigEntity entity = new DictConfigEntity();
            entity.setCode(code);
            entity.setName(code);
            entity.setValue("常用");
            entity.setScore(100l);
            entity.setStatus(true);
            entity = dictConfigDAO.save(entity);
            DictConfigResponseVO dict = new DictConfigResponseVO();
            BeanUtils.copyProperties(entity, dict);
            list.add(dict);
            refreshDictConfigCache(code);
        }
        return list;
    }

    public DictConfigResponseVO getLatestDictConfigVOListFromCache(String code) {
        String key = RedisKeyEnum.DICT_CONFIG_LIST_CACHE.getKey(code);
        String val = redisUtil.get(key);
        List<DictConfigResponseVO> dictConfigResponseVOS = null;
        if (StringUtils.isNotBlank(val)) {
            dictConfigResponseVOS = JsonUtil.fromJson(val, new TypeReference<List<DictConfigResponseVO>>() { });
        }
        if (CollectionUtils.isNotEmpty(dictConfigResponseVOS)) {
            return dictConfigResponseVOS.get(0);
        }
        return null;
    }

    public DictConfigResponseVO getDictConfigVOListFromCache(String code, String name) {
        List<DictConfigResponseVO> dictConfigResponseVOS = getDictConfigVOListFromCache(code);
        for (DictConfigResponseVO vo :dictConfigResponseVOS) {
            if (vo.getName().equals(name)) {
                return vo;
            }
        }
        return null;
    }

    public List<DictConfigResponseVO> getDictConfigListFromCache(String code, String name) {
        List<DictConfigResponseVO> dictConfigResponseVOS = getDictConfigVOListFromCache(code);
        if (CollectionUtils.isEmpty(dictConfigResponseVOS)) {
            return Collections.emptyList();
        }
        return dictConfigResponseVOS.stream().filter(dict ->
                dict.getName().equals(name)).collect(Collectors.toList());
    }

    public PAIPageResponseBeanUtil<DictConfigResponseVO> getListByCondition(String code, String name, String value, int pageNo, int pageSize) {

        Pageable pageable = PageRequest.of(pageNo-1, pageSize, Sort.by(Sort.Direction.DESC, "score"));
        Specification<DictConfigEntity> specification = new Specification<DictConfigEntity>() {
            @Override
            public Predicate toPredicate(Root<DictConfigEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                if (StringUtils.isNotBlank(code)) {
                    predicates.add(criteriaBuilder.like(root.get("code").as(String.class), "%" + code + "%"));
                }
                if (StringUtils.isNotBlank(name)) {
                    predicates.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + name + "%"));
                }
                if (StringUtils.isNotBlank(value)) {
                    predicates.add(criteriaBuilder.like(root.get("value").as(String.class), "%" + value + "%"));
                }
                Predicate[] pre = new Predicate[predicates.size()];
                criteriaQuery.where(predicates.toArray(pre));
                return criteriaQuery.getRestriction();
            }
        };
        Page<DictConfigEntity> dictConfigEntities = dictConfigDAO.findAll(specification, pageable);
        List<DictConfigResponseVO> dictConfigResponseVOS = new ArrayList<>();
        if (dictConfigEntities != null && !CollectionUtils.isEmpty(dictConfigEntities.getContent())) {
            for (DictConfigEntity dictConfigEntity : dictConfigEntities.getContent()) {
                DictConfigResponseVO dictConfigResponseVO = new DictConfigResponseVO();
                BeanUtils.copyProperties(dictConfigEntity, dictConfigResponseVO);
                if (dictConfigEntity.getUpdateDate() != null) {
                    dictConfigResponseVO.setUpdateDateStr(DateUtils.getDate2String(dictConfigEntity.getUpdateDate()));
                }
                dictConfigResponseVOS.add(dictConfigResponseVO);
            }
        }
        return PAIPageResponseBeanUtil.success(pageNo, pageSize, dictConfigEntities.getTotalElements(), dictConfigResponseVOS);
    }

    private void refreshDictConfigCache(String code) {
        String key = RedisKeyEnum.DICT_CONFIG_LIST_CACHE.getKey(code);
        redisUtil.remove(key);

        List<DictConfigEntity> entityList = dictConfigDAO.findAllByCodeAndStatusOrderByScoreDesc(code, Boolean.TRUE);
        List<DictConfigResponseVO> vos = convertVoList(entityList);
        redisUtil.set(key, JsonUtil.toJsonString(vos));
    }

    private List<DictConfigResponseVO> convertVoList(List<DictConfigEntity> entityList) {
        List<DictConfigResponseVO> list = new ArrayList<>();
        if (CollectionUtils.isEmpty(entityList)) {
            return list;
        }
        for (DictConfigEntity dictConfigEntity :entityList) {
            DictConfigResponseVO vo = new DictConfigResponseVO();
            BeanUtils.copyProperties(dictConfigEntity, vo);
            if (dictConfigEntity.getUpdateDate() != null) {
                vo.setUpdateDateStr(DateUtils.getDate2String(dictConfigEntity.getUpdateDate()));
            }
            list.add(vo);
        }
        return list;
    }

    private DictConfigEntity convertVoToEntity(DictConfigSaveOrUpdateVO vo, String userId) {

        DictConfigEntity entity;
        Date now = new Date();
        if (vo.getId() != null) {
            entity = dictConfigDAO.findAllById(vo.getId());
            Assert.isTrue(entity != null, "字典不存在");
        } else {
            entity = new DictConfigEntity();
            entity.setCreateBy(userId);
            entity.setCreateDate(now);
            entity.setStatus(Boolean.FALSE);
        }
        entity.setCode(vo.getCode());
        entity.setName(vo.getName());
        entity.setValue(vo.getValue());
        entity.setExt(vo.getExt());
        entity.setScore(vo.getScore());
        entity.setUpdateBy(userId);
        entity.setUpdateDate(now);
        return entity;
    }
}
